#include <iostream>
#include <string.h>
#include <cassert>
using std::cout;
using std::endl;

class Cowstring{
public:
    // 构造函数与析构函数
    Cowstring();
    Cowstring(const char* pstr);
    ~Cowstring();

    // 常见操作
    Cowstring(const Cowstring& rhs);    // 浅拷贝
    Cowstring& operator=(const Cowstring& rhs);   // 赋值
    char& operator[](size_t index);     // 下标运算符
    
    // 辅助函数
    const char* c_str() const;

private:
    char* _pstr;
};

Cowstring::Cowstring()
    :_pstr(new char[1 + 4]() + 4){
    *(int*)(_pstr - 4) = 1;
}

// 注意参数不是(const CowString *rhs)
// 出现expected unqualified-id，很可能是没有加Cowstring
Cowstring::Cowstring(const char* pstr)
    :_pstr(new char[strlen(pstr) + 1 + 4]() + 4){
        strcpy(_pstr, pstr);
        *(int*)(_pstr - 4) = 1;
    }

// 每次对象析构时都会-1，直到==0为止才会释放内存
// 指针可能复用的情况需置空，全局资源必须置空
Cowstring::~Cowstring(){
    if(--*(int*)(_pstr - 4) == 0){  
        delete [](_pstr - 4);
        _pstr = nullptr;
    }
}

Cowstring::Cowstring(const Cowstring& rhs)
    :_pstr(rhs._pstr){
        ++*(int *)(_pstr - 4);
    }

// 记得返回引用
Cowstring& Cowstring::operator=(const Cowstring& rhs){
    if(this != &rhs){
        if(--*(int*)(_pstr - 4) == 0){
            delete [](_pstr - 4);
        }

        _pstr = rhs._pstr;
        ++*(int*)(_pstr - 4);
    }

    return *this;
}
    
char& Cowstring::operator[](size_t index){
    if(index >= strlen(_pstr)){
//        static char temp = '\0';  // 注意加static，否则会引发未定义行为
//        return temp;
    
        // AI的推荐写法
        throw std::out_of_range("Cowstring::operator[] index out of range");
    }

    if(*(int*)(_pstr - 4) > 1){
        --*(int *)(_pstr - 4);
        char* temp = new char[strlen(_pstr) + 1 + 4]() + 4;
        strcpy(temp, _pstr);
        _pstr = temp;
        *(int *)(_pstr - 4) = 1;
    }

    return _pstr[index]; 
}

const char* Cowstring::c_str() const{
    return _pstr;
}

void test_cowstring() {
    // ==================== 基础构造测试 ====================
    Cowstring s1("Hello");
    assert(strcmp(s1.c_str(), "Hello") == 0);
    std::cout << "1. 基础构造测试通过" << std::endl;

    // ==================== 拷贝构造测试 ====================
    Cowstring s2 = s1;  // 拷贝构造
    assert(*(int*)(s1.c_str() - 4) == 2);  // 引用计数=2
    assert(strcmp(s2.c_str(), "Hello") == 0);
    std::cout << "2. 拷贝构造测试通过" << std::endl;

    // ==================== 写时复制(COW)测试 ====================
    s2[0] = 'h';  // 应触发COW
    assert(*(int*)(s1.c_str() - 4) == 1);  // s1引用计数降为1
    assert(*(int*)(s2.c_str() - 4) == 1);  // s2引用计数为1（新内存）
    assert(strcmp(s1.c_str(), "Hello") == 0);  // s1不变
    assert(strcmp(s2.c_str(), "hello") == 0);  // s2已修改
    std::cout << "3. 写时复制测试通过" << std::endl;

    // ==================== 赋值运算符测试 ====================
    Cowstring s3;
    s3 = s1;  // 赋值操作
    assert(*(int*)(s1.c_str() - 4) == 2);  // 引用计数=2
    assert(strcmp(s3.c_str(), "Hello") == 0);
    std::cout << "4. 赋值运算符测试通过" << std::endl;

    // ==================== 下标访问测试 ====================
    assert(s3[1] == 'e');
    s3[1] = 'a';  // 修改字符
    assert(strcmp(s3.c_str(), "Hallo") == 0);
    assert(*(int*)(s1.c_str() - 4) == 1);  // s1引用计数因COW降为1
    std::cout << "5. 下标访问测试通过" << std::endl;

    // ==================== 引用计数测试 ====================
    {
        Cowstring s4 = s1;
        assert(*(int*)(s1.c_str() - 4) == 2);
    }  // s4析构后
    assert(*(int*)(s1.c_str() - 4) == 1);  // s1引用计数恢复1
    std::cout << "6. 引用计数测试通过" << std::endl;

    // ==================== 异常测试 ====================
    try {
        s1[10] = '!';  // 越界访问
        assert(false);  // 不应执行到此处
    } catch (const std::out_of_range& e) {
        assert(strstr(e.what(), "out of range") != nullptr);
        std::cout << "7. 异常测试通过: " << e.what() << std::endl;
    }
}

int main() {
    test_cowstring();
    std::cout << "===== 所有测试通过 =====" << std::endl;
    return 0;
}
